﻿using mozhi.smarterp.Finance.Accounts;
using mozhi.smarterp.Finance.Accounts.Repository;
using mozhi.smarterp.Finance.Banks;
using mozhi.smarterp.Finance.Basedatas.Employees;
using mozhi.smarterp.Finance.Basedatas.Events;
using mozhi.smarterp.Finance.Basedatas.ExpenseItems;
using mozhi.smarterp.Finance.Basedatas.Repository;
using mozhi.smarterp.Finance.Basedatas.Services;
using mozhi.smarterp.Finance.Querys;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Guids;

namespace mozhi.smarterp.Finance.Basedatas
{
    public class ExpenseItemAppService : BaseDataAppService<ExpenseItem , ExpenseItemDto, ExpenseItemCreateDto, ExpenseItemUpdateDto>, IExpenseItemAppService
    {
        private ExpenseItemManager _manager;
        private IAccountRepository _accountRepository;
        private IDimensionGroupValueRepository _dimensionGroupValueRepository;
        public ExpenseItemAppService(IBaseDataRepository<ExpenseItem> repository, IDataAssociationRepository dataAssociationRepository, 
            IGuidGenerator guidGenerator, IDistributedEventBus distributedEventBus , IDimensionGroupValueRepository dimensionGroupValueRepository, ExpenseItemManager manager) 
            : base(repository, dataAssociationRepository, guidGenerator, distributedEventBus)
        {
            _manager = manager;
            _dimensionGroupValueRepository = dimensionGroupValueRepository;
        }

        public async Task<PagedResultDto<ExpenseItemDto>> FindAsync(ExpenseItemPageQuery query)
        {
            var items = await _repository.FindAsync(query);

            var total = await _repository.GetCountAsync(query);

            var result = new PagedResultDto<ExpenseItemDto>();

            if(items.Count==0)
                return result;


            result.TotalCount = total;
            result.Items = ObjectMapper.Map<List<ExpenseItem>, List<ExpenseItemDto>>(items);

            await LoadAccountInfoAsync(result.Items.ToList());

            return result;

        }

        public override async Task<ExpenseItemDto> CreateAsync(ExpenseItemCreateDto dto)
        {
            var tuple = await _manager.CreateAsync(dto.Code, dto.Name, dto.ParentId, dto.ExpenseAccountId);

            var expenseItem = tuple.Item1;

            var parent = tuple.Item2;

            var dimensionGroupValues = tuple.Item3;

            expenseItem = await _repository.InsertAsync(expenseItem);

            if(parent!=null)
                await _repository.UpdateAsync(parent);

            if (dimensionGroupValues.Count > 0)
                await _dimensionGroupValueRepository.UpdateAsync(dimensionGroupValues);

            var result = ObjectMapper.Map<ExpenseItem, ExpenseItemDto>(expenseItem);

            await LoadAccountInfoAsync(new List<ExpenseItemDto>() { result });

            return result;
        }


        public override async Task<ExpenseItemDto> UpdateAsync(ExpenseItemUpdateDto dto)
        {
            var tuple = await _manager.UpdateAsync(dto.Id, dto.Code, dto.Name, dto.ExpenseAccountId ,dto.Activated);

            var expenseItem = tuple.Item1;

            var result = ObjectMapper.Map<ExpenseItem, ExpenseItemDto>(expenseItem);

            await LoadAccountInfoAsync(new List<ExpenseItemDto>() { result });

            return result;
        }

        public override async Task<ExpenseItemDto> DeleteAsync(Guid id)
        {
            var tuple = await _manager.DeleteAsync(id);

            var expenseItem = tuple.Item1;

            var parent = tuple.Item2;

            var dimensionGroupValues = tuple.Item3;

            await _repository.DeleteAsync(expenseItem);

            await _distributedEventBus.PublishAsync(new DataAssociationRemoveEvent(expenseItem.Id, expenseItem.ExpenseAccountId.Value));

            if (parent != null)
                await _repository.UpdateAsync(parent);

            if (dimensionGroupValues.Count > 0)
                await _dimensionGroupValueRepository.UpdateAsync(dimensionGroupValues);

            var result = ObjectMapper.Map<ExpenseItem, ExpenseItemDto>(expenseItem);

            return result;
        }

        #region
        private async Task LoadAccountInfoAsync(List<ExpenseItemDto> expenseItems)
        {
            var accountIds = expenseItems.Where(x => x.ExpenseAccountId != default).Select(x => x.ExpenseAccountId.Value).Distinct().ToList();

            if (accountIds.Count == 0)
                return;

            var accounts = await _accountRepository.FindAsync(new AccountQuery() { Ids = accountIds });

            foreach (var expenseItem in expenseItems)
            {
                expenseItem.ExpenseAccountName = accounts.FirstOrDefault(x => x.Id == expenseItem.ExpenseAccountId)?.FullName;
            }
        }
        #endregion
    }
}
